package com.app.backend.config.feign;

import feign.*;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;
import feign.jackson.JacksonDecoder;
import feign.okhttp.OkHttpClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.cloud.openfeign.support.SpringMvcContract;
import org.springframework.context.annotation.Bean;

//import feign.jackson.JacksonDecoder;

/**
 * @author Jet Zheng
 */
@Slf4j
public class FeignConfiguration {

    private static final int CONNECT_TIMEOUT_MILLIS = 3000;
    private static final int READ_TIMEOUT_MILLIS = 60000;
    private static final Logger LOGGER = new Logger() {
        @Override
        protected void log(String configKey, String format, Object... objects) {
            log.info(String.format(configKey + format + "%n", objects));
        }
    };

    public static final class FeignNormalConfiguration {
        @Bean
        public Logger.Level loggerLevel() {
            return Logger.Level.FULL;
        }

        @Bean
        public Logger logger() {
            return LOGGER;
        }

        @Bean
        public Contract contract() {
            return new SpringMvcContract();
        }

        @Bean
        public Client feignClient(okhttp3.OkHttpClient okHttpClient) {
            return new OkHttpClient(okHttpClient);
        }

        @Bean
        public Request.Options options() {
            return new Request.Options(CONNECT_TIMEOUT_MILLIS, READ_TIMEOUT_MILLIS);
        }

        @Bean
        public Retryer retryer() {
            return Retryer.NEVER_RETRY;
        }

    }

    public static final class FeignObjectFromAndStringConfiguration {
        @Bean
        public Encoder feignEncoder() {
            return new FeignObjectToFormEncoder();
        }

        @Bean
        public Logger.Level loggerLevel() {
            return Logger.Level.FULL;
        }

        @Bean
        public Logger logger() {
            return LOGGER;
        }

        @Bean
        public Contract contract() {
            return new SpringMvcContract();
        }

        @Bean
        public Client feignClient(okhttp3.OkHttpClient okHttpClient) {
            return new OkHttpClient(okHttpClient);
        }

        @Bean
        public Request.Options options() {
            return new Request.Options(CONNECT_TIMEOUT_MILLIS, READ_TIMEOUT_MILLIS);
        }

        @Bean
        public Retryer retryer() {
            return Retryer.NEVER_RETRY;
        }

    }

    public static final class FeignObjectFormConfiguration {
        @Bean
        public Encoder feignEncoder() {
            return new FeignObjectToFormEncoder();
        }

        @Bean
        public Logger.Level loggerLevel() {
            return Logger.Level.FULL;
        }

        @Bean
        public Logger logger() {
            return LOGGER;
        }

        @Bean
        public Contract contract() {
            return new SpringMvcContract();
        }

        @Bean
        public Client feignClient(okhttp3.OkHttpClient okHttpClient) {
            return new OkHttpClient(okHttpClient);
        }

        @Bean
        public Request.Options options() {
            return new Request.Options(CONNECT_TIMEOUT_MILLIS, READ_TIMEOUT_MILLIS);
        }

        @Bean
        public Retryer retryer() {
            return Retryer.NEVER_RETRY;
        }

        @Bean
        public Decoder feignDecoder(ObjectFactory<HttpMessageConverters> messageConvert) {
            return new SpringDecoder(messageConvert);
        }
    }

    public static final class FeignObjectUrlParamConfiguration {
        @Bean
        public Encoder feignEncoder() {
            return new FeignObjectToUrlParamEncoder();
        }

        @Bean
        public Logger.Level loggerLevel() {
            return Logger.Level.FULL;
        }

        @Bean
        public Logger logger() {
            return LOGGER;
        }

        @Bean
        public Contract contract() {
            return new SpringMvcContract();
        }

        @Bean
        public Client feignClient(okhttp3.OkHttpClient okHttpClient) {
            return new OkHttpClient(okHttpClient);
        }

        @Bean
        public Request.Options options() {
            return new Request.Options(CONNECT_TIMEOUT_MILLIS, READ_TIMEOUT_MILLIS);
        }

        @Bean
        public Retryer retryer() {
            return Retryer.NEVER_RETRY;
        }

        @Bean
        public Decoder feignDecoder(ObjectFactory<HttpMessageConverters> messageConvert) {
            return new SpringDecoder(messageConvert);
        }
    }

    public static final class FeignObjectFormJsonResultConfiguration {
        @Bean
        public Encoder feignEncoder() {
            return new FeignObjectToFormEncoder();
        }

        @Bean
        public Logger.Level loggerLevel() {
            return Logger.Level.FULL;
        }

        @Bean
        public Logger logger() {
            return LOGGER;
        }

        @Bean
        public Contract contract() {
            return new SpringMvcContract();
        }

        @Bean
        public Client feignClient(okhttp3.OkHttpClient okHttpClient) {
            return new OkHttpClient(okHttpClient);
        }

        @Bean
        public Request.Options options() {
            return new Request.Options(CONNECT_TIMEOUT_MILLIS, READ_TIMEOUT_MILLIS);
        }

        @Bean
        public Retryer retryer() {
            return Retryer.NEVER_RETRY;
        }

        @Bean
        public Decoder feignDecoder() {
            return new JacksonDecoder();
        }
    }

    public static final class FeignSpringConfiguration {

        @Bean
        public Decoder feignDecoder(ObjectFactory<HttpMessageConverters> messageConvert) {
            return new SpringDecoder(messageConvert);
        }

        @Bean
        public Encoder feignEncoder(ObjectFactory<HttpMessageConverters> messageConvert) {
            return new SpringFormEncoder(new SpringEncoder(messageConvert));
        }

        @Bean
        public Logger.Level loggerLevel() {
            return Logger.Level.FULL;
        }

        @Bean
        public Logger logger() {
            return LOGGER;
        }

        @Bean
        public Contract contract() {
            return new SpringMvcContract();
        }

        @Bean
        public Client feignClient(okhttp3.OkHttpClient okHttpClient) {
            return new OkHttpClient(okHttpClient);
        }

        @Bean
        public Request.Options options() {
            return new Request.Options(CONNECT_TIMEOUT_MILLIS, READ_TIMEOUT_MILLIS);
        }

        @Bean
        public Retryer retryer() {
            return Retryer.NEVER_RETRY;
        }
    }

    public static final class FeignSpringJsonResultConfiguration {

        @Bean
        public Decoder feignDecoder() {
            return new JacksonDecoder();
        }

        @Bean
        public Encoder feignEncoder(ObjectFactory<HttpMessageConverters> messageConvert) {
            return new SpringFormEncoder(new SpringEncoder(messageConvert));
        }

        @Bean
        public Logger.Level loggerLevel() {
            return Logger.Level.FULL;
        }

        @Bean
        public Logger logger() {
            return LOGGER;
        }

        @Bean
        public Contract contract() {
            return new SpringMvcContract();
        }

        @Bean
        public Client feignClient(okhttp3.OkHttpClient okHttpClient) {
            return new OkHttpClient(okHttpClient);
        }

        @Bean
        public Request.Options options() {
            return new Request.Options(CONNECT_TIMEOUT_MILLIS, READ_TIMEOUT_MILLIS);
        }

        @Bean
        public Retryer retryer() {
            return Retryer.NEVER_RETRY;
        }
    }
}
